/*
 * Unidata Platform
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 *
 * Commercial License
 * This version of Unidata Platform is licensed commercially and is the appropriate option for the vast majority of use cases.
 *
 * Please see the Unidata Licensing page at: https://unidata-platform.com/license/
 * For clarification or additional options, please contact: info@unidata-platform.com
 * -------
 * Disclaimer:
 * -------
 * THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND
 * REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
 * IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, NON-INFRINGEMENT, PERFORMANCE AND
 * THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING.
 */
package org.unidata.mdm.data.service.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.unidata.mdm.core.service.MetaModelService;
import org.unidata.mdm.core.util.SecurityUtils;
import org.unidata.mdm.data.dao.FavoriteEtalonsDAO;
import org.unidata.mdm.data.service.FavoriteEtalonsService;
import org.unidata.mdm.meta.configuration.Descriptors;
import org.unidata.mdm.meta.type.instance.DataModelInstance;
import org.unidata.mdm.system.service.AfterModuleStartup;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.multimap.MultiMap;

/**
 * @author Alexey Tsarapkin
 */
@Service
public class FavoriteEtalonsServiceImpl implements AfterModuleStartup, FavoriteEtalonsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(FavoriteEtalonsServiceImpl.class);
    /**
     * The hazelcast instance.
     */
    @Autowired
    private HazelcastInstance hazelcastInstance;

    /**
     * The etalon favorites dao.
     */
    @Autowired
    private FavoriteEtalonsDAO dao;

    @Autowired
    private MetaModelService metaModelService;
    /**
     * The favoriteEtalons uuid - key, user:entityName value
     */
    private MultiMap<UUID, String> etalonUsers;

    @Override
    public void afterModuleStartup() {
        etalonUsers = hazelcastInstance.getMultiMap("favoriteEtalonUsers");
        if (etalonUsers.size() == 0) {
            dao.getAllFavorites((createdBy, uuid) -> etalonUsers.put(uuid, createdBy), 1000);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void add(Map<String, List<UUID>> favorites) {
        favorites.forEach((entityName, etalons) ->
            etalons.forEach(uuid -> {
                if (etalonUsers.put(uuid, SecurityUtils.getCurrentUserName())) {
                    dao.add(favorites);
                }
            })
        );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void remove(UUID favorite) {
        if (etalonUsers.remove(favorite) != null) {
            dao.removeUUID(favorite);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void exclude(UUID favorite) {
        if(etalonUsers.remove(favorite, SecurityUtils.getCurrentUserName())){
            dao.exclude(favorite);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void exclude(List<UUID> favorites) {
        String currentUserName = SecurityUtils.getCurrentUserName();
        favorites.forEach(e -> {
            if(etalonUsers.remove(e, currentUserName)){
                dao.exclude(e);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void excludeByEntity(String entityName, String userName) {
        dao.getEtalons(entityName).forEach(e -> etalonUsers.remove(e, userName));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeAllByEntity(String entityName) {
        dao.getAllEtalons(entityName).forEach(e -> etalonUsers.remove(e));
        dao.removeAllByEntity(entityName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isFavorite(UUID uuid) {
        Collection<String> userEntity = etalonUsers.get(uuid);
        if (CollectionUtils.isEmpty(userEntity)) {
            return false;
        }
        return userEntity.contains(SecurityUtils.getCurrentUserName());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<UUID> getEtalons() {
        return dao.getEtalons();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<UUID> getEtalons(String entityName) {
        return dao.getEtalons(entityName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, List<UUID>> getEtalonsMap() {
        return dao.getEtalonsMap();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, List<UUID>> getEtalonsMap(String entityName) {
        return dao.getEtalonsMap(entityName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeAbsentEntityFavorites() {
        try {
            DataModelInstance i = metaModelService.instance(Descriptors.DATA);
            dao.getFavoriteEntityNames().forEach(name -> {
                if (!i.isRegister(name) && !i.isLookup(name)) {
                    removeAllByEntity(name);
                }
            });
        } catch (Exception e) {
            LOGGER.warn(e.getMessage(), e);
        }
    }

}
